﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Xml;
using System.DirectoryServices;
using System.DirectoryServices.AccountManagement;


namespace QuickJoin
{
    public partial class frmMain : Form
    {
        static string configFile = Path.GetDirectoryName(Application.ExecutablePath) + "\\" + "Config.xml";
        static string logfile = Path.GetDirectoryName(Application.ExecutablePath) + "\\" + "Quickjoin.log";
        DirectoryEntry groupObject = new DirectoryEntry();
        static string currentDomain;
        static string currentClass;
        Dictionary<string, string> domainList = new Dictionary<string, string>(StringComparer.CurrentCultureIgnoreCase);

        public frmMain()
        {
            InitializeComponent();
            readConfig();
            passGroupnameFromArguments();
        }

        private void passGroupnameFromArguments()
        {
            string[] args = Environment.GetCommandLineArgs();

            for (int i = 0; i < args.Length; i++)
            {
                // args[0] is exepath, daarna komen eventuele echte argumenten.
                if (i == 1)
                {
                    tbGroupName.Text = args[i];
                    tbGroupName.SelectionStart = tbGroupName.Text.Length;
                }
            }
        }

        // return domain adsPath
        private string getDomainAdsPath(string groupdomain)
        {
            string adsPath = "Unknown";
            if (domainList.ContainsKey(groupdomain))
            {
                adsPath = domainList[groupdomain];
            }
            return adsPath;
        }

        private string getGroupDomain(string groupname)
        {
            // Gaat er vanuit dat de groupname begint met het domein gevolgt door -GS-
            // Oxyo-GS-Smart Technologies Smart Sync Student
            string domain = "Unknown";
            int cnLength = groupname.IndexOf("-GS-", StringComparison.CurrentCultureIgnoreCase);
            if (cnLength >= 0)
            {
                domain = groupname.Substring(0, cnLength).ToLower();
            }
            return domain;
        }

        // Find out if group is user or computer based (important for sccm collection)
        // this should be part of the group description
        private string getGroupClass(string groupDescription)
        {
            string objectclass;
            if (groupDescription.IndexOf("user", System.StringComparison.OrdinalIgnoreCase) > 0)
            {
                objectclass = "user";
            }
            else if (groupDescription.IndexOf("workstation", System.StringComparison.OrdinalIgnoreCase) > 0)
            {
                objectclass = "computer";
            }
            else
            {
                objectclass = "unknown";
            }
            return objectclass;
        }

        // Read config.xml and get domains and objects
        void readConfig()
        {
            TableLayoutPanel currentTable = tableLayout1;
            string domain = "Unknown";
            string adsPath = "";
            string checkboxName;
            string checkboxText;
            Int16 d = 0;
            Int16 c = 0;
            Int16 u = 0;

            if (File.Exists(configFile))
            {
                FileStream stream = new FileStream(configFile, FileMode.Open);
                XmlReader xmlReader = XmlReader.Create(stream);
                try
                {
                    while (xmlReader.Read())
                    {
                        if (xmlReader.IsStartElement())
                        {
                            switch (xmlReader.Name)
                            {
                                case "Domain":
                                    if (xmlReader.HasAttributes)
                                    {
                                        domain = xmlReader.GetAttribute("name").ToLower();
                                        adsPath = xmlReader.GetAttribute("AdsPath");
                                        domainList.Add(domain, adsPath);
                                        // Check if this is the first or second domain
                                        // Only two domains are supported
                                        switch (d)
                                        {
                                            case 0:
                                                u = 0;
                                                c = 0;
                                                groupBox1.Text = domain.ToUpper();
                                                currentTable = tableLayout1;
                                                break;
                                            case 1:
                                                u = 0;
                                                c = 0;
                                                groupBox2.Text = domain.ToUpper();
                                                currentTable = tableLayout2;
                                                break;
                                        }
                                        d += 1;
                                        break;
                                    }
                                    break;
                                case "User":
                                    // Checkboxes are named: oxyo-user-0 etc.
                                    checkboxName = domain + "-user-" + u.ToString();
                                    checkboxText = xmlReader.GetAttribute("name");
                                    addCheckBox(checkboxName, checkboxText, currentTable, u, 0); // name, text, table, row, column
                                    u += 1;
                                    break;
                                case "Workstation":
                                    // Checkboxes are named: oxyo-computer-0 etc.
                                    checkboxName = domain + "-computer-" + c.ToString();
                                    checkboxText = xmlReader.GetAttribute("name");
                                    addCheckBox(checkboxName, checkboxText, currentTable, c, 1); // name, text, table, row, column
                                    c += 1;
                                    break;
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    MessageBox.Show(e.Message);
                }
                finally
                {
                    stream.Close();
                    xmlReader.Close();
                }
            }
        }

        private void addCheckBox(string name, string text, TableLayoutPanel table, Int16 row, Int16 column)
        {
            CheckBox checkBox1 = new CheckBox();
            checkBox1.Size = new System.Drawing.Size(120, 24);
            checkBox1.TabIndex = 1;
            checkBox1.UseVisualStyleBackColor = true;
            // add control to column, row. Zero based
            table.Controls.Add(checkBox1, column, row);
            checkBox1.Name = name;
            checkBox1.Text = text;
        }

        // Voeg geselecteerde objecten toe aan group
        private void addSelectedObjectsToGroup()
        {
            TableLayoutPanel temptable = tableLayout1;
            string groupDN = groupObject.Properties["distinguishedName"].Value.ToString();
            for (int i = 1; i <= 2; i++)
            {
                switch (i)
                {
                    case 1:
                        temptable = tableLayout1;
                        break;
                    case 2:
                        temptable = tableLayout2;
                        break;
                }

                foreach (Control cbox in temptable.Controls)
                {
                    if (cbox is CheckBox)
                    {
                        if (((CheckBox)cbox).Checked)
                        {
                            // checkboxes are named: domain-class-i
                            int endDomain = cbox.Name.IndexOf("-");
                            int endClass = cbox.Name.IndexOf("-", endDomain + 1);
                            string objectDomain = cbox.Name.Substring(0, endDomain).ToLower();
                            string objectClass = cbox.Name.Substring(endDomain + 1, endClass - endDomain - 1);

                            if (objectDomain == currentDomain)
                            {
                                if (objectClass == currentClass || currentClass == "unknown")
                                    {
                                        DirectoryEntry memberObject = getObject(objectClass, cbox.Text, getDomainAdsPath(currentDomain));
                                        string adObjectDN = memberObject.Properties["distinguishedName"].Value.ToString();
                                        if (!isMemberOf(memberObject, groupDN))
                                        {
                                            string groupLDAPstring = groupObject.Path;
                                            if (addToGroup(groupLDAPstring, adObjectDN))
                                            {
                                                tbResult.AppendText(cbox.Text + " toegevoegd aan " + tbGroupName.Text + Environment.NewLine);
                                                writeLog(cbox.Text + " toegevoegd aan " + tbGroupName.Text);
                                            }
                                            else
                                            {
                                                tbResult.AppendText(cbox.Text + " mislukt." + Environment.NewLine);
                                            }
                                        }
                                        else
                                        {
                                            tbResult.AppendText(cbox.Text + " is al lid." + Environment.NewLine);
                                        }
                                    }
                                    else
                                    {
                                        tbResult.AppendText(cbox.Text + " niet toegevoegd, verkeerde class." + Environment.NewLine);
                                    }
                            }
                            else
                            {
                                tbResult.AppendText(cbox.Text + " niet toegevoegd, verkeerde domein." + Environment.NewLine);
                            }
                        }
                    }
                }
            }
        }

        // groupPath is complete ldap path including servername
        // adObjectDN is distinguished name without the ldap:/ / part
        private bool addToGroup(string groupPath, string adObjectDN)
        {
            bool result = false;
            // Todo check if object is already member of group.
            // if ismember result = adObjectDN + " is al lid van groep."
            try
            {
                DirectoryEntry group = new DirectoryEntry(groupPath);
                DirectoryEntry member = new DirectoryEntry(adObjectDN);
                group.Properties["member"].Add(adObjectDN);
                group.CommitChanges();
                group.Close();
                result = true;
            }
            catch (System.DirectoryServices.DirectoryServicesCOMException E)
            {
                MessageBox.Show(E.Message.ToString());
            }
            return result;
        }

        // Check if user is member of group
        // groupDN is distinguished name without the ldap:/ / part
        private bool isMemberOf(DirectoryEntry adObject, string groupDN)
        {
            bool ismember = false;
            try
            {
                PropertyValueCollection groups = adObject.Properties["memberOf"];
                foreach (string g in groups)
                {
                    // g contains Distinguishedname
                    if (g.Equals(groupDN))
                    {
                        ismember = true;
                    }
                }
            }
            catch (System.DirectoryServices.DirectoryServicesCOMException E)
            {
                MessageBox.Show(E.Message.ToString());
            }
            return ismember;
        }

        //Find and return directory object.
        private DirectoryEntry getObject(string objectCls, string adObject, string LdapDomain)
        {
            DirectoryEntry de = new DirectoryEntry();
            SearchResult results = null;
            // set the ldap base, depending on the selected domain
            de.Path = LdapDomain;
            DirectorySearcher search = new DirectorySearcher(de);
            if (objectCls == "user")
            {
                search.Filter = "(&(objectClass=" + objectCls + ")(sAMAccountName=" + adObject + "))";
            }
            else
            {
                search.Filter = "(&(objectClass=" + objectCls + ")(cn=" + adObject + "))";
            }
            // search.Filter = "(&(objectClass=" + objectCls + ")(cn=" + adObject + "))";
            search.PropertiesToLoad.Add("description");
            search.PropertiesToLoad.Add("distinguishedName");
            try
            {
                results = search.FindOne();
                if (results != null)
                {
                    de = results.GetDirectoryEntry();
                }
                else 
                {
                    de = null;
                }
            }
            catch (Exception e)
            {
                de = null;
                MessageBox.Show(e.Message);
            }
            finally
            {
                search.Dispose();
                results = null;
            }

            return de;
        }

        private void processManualInput(string adObject)
        {
            DirectoryEntry manualInput = getObject("computer", adObject, getDomainAdsPath(currentDomain));
            string objectCls = "unknown";
            if (manualInput != null)
            {
                objectCls = "computer";
            }
            else
            {
                manualInput = getObject("user", adObject, getDomainAdsPath(currentDomain));
                if (manualInput != null)
                {
                    objectCls = "user";
                }
            }

            if (manualInput != null)
            {
                string groupDN = groupObject.Properties["distinguishedName"].Value.ToString();
                string adObjectDN = manualInput.Properties["distinguishedName"].Value.ToString();
                string groupLDAPstring = groupObject.Path;
                if (objectCls == currentClass || currentClass == "unknown")
                {
                    if (!isMemberOf(manualInput, groupDN))
                    {
                        if (addToGroup(groupLDAPstring, adObjectDN))
                        {
                            tbResult.AppendText(tbCustom.Text + " toegevoegd aan " + tbGroupName.Text + Environment.NewLine);
                            writeLog(tbCustom.Text + " toegevoegd aan " + tbGroupName.Text);
                        }
                        else
                        {
                            tbResult.AppendText(tbCustom.Text + " toegevoegen mislukt" + Environment.NewLine);
                            writeLog(tbCustom.Text + " toegevoegen mislukt");
                        }
                    }
                    else
                    {
                        tbResult.AppendText(tbCustom.Text + " is al lid." + Environment.NewLine);
                    }
                }
                else
                {
                    tbResult.AppendText(tbCustom.Text + " niet toegevoegd. Verkeerde Class." + Environment.NewLine);
                }
            }
            else
            {
                tbResult.AppendText(tbCustom.Text + " niet gevonden in " + currentDomain + Environment.NewLine);
                writeLog(tbCustom.Text + " niet gevonden in " + currentDomain);
            }
        }

        // Get object description. 
        // Return "?" if null.
        private string getDescription(DirectoryEntry adObject)
        {
            if (adObject.Properties["Description"].Value != null)
            {
                return adObject.Properties["Description"].Value.ToString();
            }
            else
                return "?";
        }

        // this is the start
        private void start()
        {
            currentDomain = getGroupDomain(tbGroupName.Text);
            if (currentDomain != "Unknown")
            {
                string description;
                tbDescription.Text = "";
                // Get groupObject from AD
                groupObject = getObject("group", tbGroupName.Text, getDomainAdsPath(currentDomain));
                if (groupObject == null)
                {
                    tbResult.AppendText(tbGroupName.Text + " niet gevonden." + Environment.NewLine);
                    toolStripStatusLabel.Text = "Domain:  Class:";
                }
                else
                {
                    description = getDescription(groupObject);
                    tbDescription.Text = description;
                    currentClass = getGroupClass(description);
                    toolStripStatusLabel.Text = "Domain: " + currentDomain + "  Class: " + currentClass;
                    // Evaluate checkboxes and add to group
                    addSelectedObjectsToGroup();
                    if (tbCustom.Text.Length > 2)
                        processManualInput(tbCustom.Text);
                }
            }
            else
            {
                tbResult.AppendText("Groepnaam is niet volgens naamgevings conventie." + Environment.NewLine);
            }
        }

        private void writeLog(string text)
        {
            TextWriter tw = new StreamWriter(logfile, true);
            // write a line of text to the file
            tw.WriteLine(DateTime.Now + " " + text);
            tw.Close();
        }

        private void btnGo_Click(object sender, EventArgs e)
        {
            start();
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void showLogToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Process notePad = new Process();
            notePad.StartInfo.FileName = "notepad.exe";
            notePad.StartInfo.Arguments = logfile;
            notePad.Start();
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            frmAbout About = new frmAbout();
            About.Show();
        }
    }
}
